package com.learning.rpc.config.spring;

import com.learning.rpc.config.ProtocolConfig;
import com.learning.rpc.config.ReferenceConfig;
import com.learning.rpc.config.RegistryConfig;
import com.learning.rpc.config.ServiceConfig;
import com.learning.rpc.config.annocation.RpcReference;
import com.learning.rpc.config.annocation.RpcService;
import com.learning.rpc.config.util.RpcBootstrap;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Field;

/**
 * ClassName: RpcPostProcessor
 * Description: 后置处理器
 * Date: 2022/5/10 22:23 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class RpcPostProcessor implements ApplicationContextAware, InstantiationAwareBeanPostProcessor {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        // 1. 服务提供者
        if (bean.getClass().isAnnotationPresent(RpcService.class)) {

            ServiceConfig serviceConfig = new ServiceConfig();
            serviceConfig.addProtocolConfig(applicationContext.getBean(ProtocolConfig.class));
            serviceConfig.addRegistryConfig(applicationContext.getBean(RegistryConfig.class));
            // 服务标注了注解 RpcService 的服务实现类
            serviceConfig.setReference(bean);

            // 设置服务接口
            RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
            if (void.class == rpcService.interfaceClass()) {
                serviceConfig.setService(bean.getClass().getInterfaces()[0]);
            } else {
                serviceConfig.setService(rpcService.interfaceClass());
            }
            serviceConfig.setVersion(rpcService.version());

            // 暴露 service 服务
            RpcBootstrap.export(serviceConfig);
        }

        // 2. 服务引用- 注入
        for (Field field : bean.getClass().getDeclaredFields()) {
            try {
                if (!field.isAnnotationPresent(RpcReference.class)) {
                    continue; // 不继续下面的代码，继续循环
                }
                // 引用相关 配置 保存在一个对象里边
                // TODO 思考：如果一个引用需要在多个类被使用
                ReferenceConfig referenceConfig = new ReferenceConfig();
                referenceConfig.addRegistryConfig(applicationContext.getBean(RegistryConfig.class));
                referenceConfig.addProtocolConfig(applicationContext.getBean(ProtocolConfig.class));
                referenceConfig.setService(field.getType());

                RpcReference tRpcReference = field.getAnnotation(RpcReference.class);
                referenceConfig.setLoadbalance(tRpcReference.loadbalance());

                // 客户单只有接口层，没有服务端的实现，需要生成代理对象
                // 设置代理对象
                Object referenceBean = RpcBootstrap.getReferenceBean(referenceConfig);
                field.setAccessible(true);
                field.set(bean, referenceBean);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return bean;
    }


}
